package com.hy.common.excel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.exception.ExcelAnalysisStopException;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.hy.common.consts.CommonConst;
import com.hy.common.consts.RedisConst;
import com.hy.common.consts.StateConst;
import com.hy.common.exception.ImportException;
import com.hy.common.pool.ThreadPool;
import com.hy.common.utils.CommonUtils;
import com.hy.common.utils.ExcelUtil;
import com.hy.common.utils.MyObjectUtils;
import com.hy.common.utils.StateUtil;
import com.hy.entity.pojo.HyProperty;
import com.hy.entity.vo.HyPropertyReadVO;
import com.hy.entity.vo.HyPropertyVO;
import com.hy.mapper.*;
import com.hy.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.ObjectUtils;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 数据导入excel监听(支持百万数据导入)
 * @author bmbfm
 */
@Slf4j
public class EntityExcelImport extends AbstractExcelImport<HyPropertyReadVO,HyProperty>{


    private HyPropertyService hyPropertyService;
    private HyPropertyMapper propertyMapper;

    private HyUserMapper userMapper;

    private HyDepartmentMapper departmentMapper;

    private HyPlaceMapper hyPlaceMapper;

    private HyPropertySortMapper sortMapper;

    private HyUnitMapper hyUnitMapper;

    private RedisTemplate redisTemplate;

    private List<HyProperty> readData=new CopyOnWriteArrayList<>();

    private Integer runTimes=0;
    private String lock;
    private String redisLock;


    private AtomicInteger count=new AtomicInteger(0);

    public EntityExcelImport() {

    }

    public Integer getRunTimes() {
        return runTimes;
    }

    public AtomicInteger getCount() {
        return count;
    }

    public void setLock(String lock) {
        this.lock = lock;
    }

    public void setRedisLock(String redisLock) {
        this.redisLock = redisLock;
    }

    public void setRedisTemplate(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    public EntityExcelImport(HyPropertyService hyPropertyService, HyUserMapper userMapper, HyDepartmentMapper departmentMapper, HyPlaceMapper hyPlaceMapper, HyPropertySortMapper sortMapper, HyUnitMapper hyUnitMapper,
                             HyPropertyMapper propertyMapper) {
        this.hyPropertyService = hyPropertyService;
        this.userMapper = userMapper;
        this.departmentMapper = departmentMapper;
        this.hyPlaceMapper = hyPlaceMapper;
        this.sortMapper = sortMapper;
        this.hyUnitMapper = hyUnitMapper;
        this.propertyMapper=propertyMapper;
    }

    public EntityExcelImport(HyPropertyService entityService) {
        this.hyPropertyService = entityService;
    }

    private  String getEPC(HyProperty property){


        String unitId = property.getUnitId().toString();
        String propertyRfid =property.getPropertyRfid().toString();
       Integer ids=Integer.parseInt(unitId+propertyRfid);
        return ExcelUtil.Bytes2HexString(ids);

    }

    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        boolean valid = validateHeader(headMap);
        if (!valid) {

            throw new RuntimeException("表头校验失败，请检查Excel文件的列名");
        }

    }
    private boolean validateHeader(Map<Integer, String> headMap) {

        Set<String> expectedHeaders=new HashSet<>();
        Collections.addAll(expectedHeaders,"单位名称","资产编号","资产名称","规格型号","资产类别","存放区域","管理人","使用人","管理部门","使用部门","供应商","品牌","取得方式"
                ,"取得日期","入账日期","凭证号","记账日期","原值(元)","资产状态");
        Set<String> actualHeaders = new HashSet<>(headMap.values());
        return actualHeaders.containsAll(expectedHeaders);
        // 检查表头是否与预期的列名一致
    }
    public void  threadInsert(HyPropertyReadVO object, AnalysisContext context)  {

        try {
            HyProperty hyProperty=new HyProperty();
            BeanUtils.copyProperties(object,hyProperty);

            String holdPlace = object.getHoldPlace();

            String propertyCode = object.getPropertyCode();

            HyPropertyVO propertyByCode = propertyMapper.getPropertyByCode(propertyCode);
            if (MyObjectUtils.isNotBlank(propertyByCode)) throw new ExcelAnalysisStopException("该资产已存在！" +(context.getCurrentRowNum()+1)+"行");

            Integer unitId= hyUnitMapper.findUnitIdByUnitName(object.getUnitName());//单位必须
            Integer sortId=sortMapper.findSortIdByUnitIDAndSortName(unitId,object.getPropertyType());//类别是必须的
            if (ObjectUtils.isEmpty(sortId)){
                throw new ExcelAnalysisStopException("找不到资产分类！"+(object.getPropertyType())+"行");
            }
            Integer placeId= !MyObjectUtils.isNotBlank(object.getHoldPlace())?CommonConst.DEFAULT_ID:hyPlaceMapper.findplaceIdByUnitIdAndPlaceName(unitId,CommonUtils.getStringAfterDash(holdPlace)); //区域是不必须的
            Integer mangerId= !MyObjectUtils.isNotBlank(object.getManagerName())?CommonConst.DEFAULT_ID:userMapper.findUserIDByUnitIdAndUserName(unitId,object.getManagerName()); //管理人是不必须的
            Integer mangerDeptId= !MyObjectUtils.isNotBlank(object.getManagerDeptName())?CommonConst.DEFAULT_ID:departmentMapper.findDeptIDByUnitIDAndDeptName(unitId,object.getManagerDeptName());
            Integer ownerId=!MyObjectUtils.isNotBlank(object.getUsedName())?CommonConst.DEFAULT_ID: userMapper.findUserIDByUnitIdAndUserName(unitId,object.getUsedName());
            Integer ownerDeptId= !MyObjectUtils.isNotBlank(object.getUsedDeptName())?CommonConst.DEFAULT_ID:departmentMapper.findDeptIDByUnitIDAndDeptName(unitId,object.getUsedDeptName());
            Integer outProperty= StateConst.OUT_PROPERTY_FALSE;
            Integer propertyState=StateUtil.getPropertyStateCode(object.getPropertyState());

            Integer propertyRFID=0;
            Integer propertyId=0;
            synchronized (RedisConst.lock){
                propertyRFID =redisTemplate.opsForValue().increment(RedisConst.UNIT_INCREMENT_RFID+unitId).intValue();
                propertyId=redisTemplate.opsForValue().increment(RedisConst.PROPERTY_INCREMENT_ID).intValue();
            }


            Long createDateTime=new Date().getTime()+ CommonConst.GMT_TIME;
            SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String dateTime = simpleDateFormat.format(new Date(createDateTime));
            hyProperty.setPropertyId(propertyId);
            hyProperty.setDel(1);
            hyProperty.setUnitId(unitId);
            hyProperty.setPropertyTypeId(sortId);
            hyProperty.setPlaceId(placeId);
            hyProperty.setManagerId(mangerId);
            hyProperty.setManagerDeptId(mangerDeptId);
            hyProperty.setOwnerId(ownerId);
            hyProperty.setOwnerDeptId(ownerDeptId);
            hyProperty.setOutProperty(outProperty);
            hyProperty.setPropertyState(propertyState.byteValue());
            hyProperty.setPropertyRfid(propertyRFID);
            hyProperty.setCreateDate(dateTime);
            hyProperty.setUpdateDate(dateTime);
            hyProperty.setEpc(getEPC(hyProperty));
            hyProperty.setSupplier(ObjectUtils.isEmpty(object.getSupplier())?"无": object.getSupplier());
            hyProperty.setBrand(object.getBrand());
            //数据存储
            if (ObjectUtils.isEmpty(hyProperty.getPropertyCode())){
                hyProperty.setPropertyCode(CommonUtils.getPropertyCode(hyProperty,sortMapper.selectById(sortId)));
            }
            readData.add(hyProperty);
            count.incrementAndGet();

            //百万数据处理方式，达到BATCH_COUNT了，需要去存储一次数据库，防止数据几万条数据在内存，容易OOM
 /*       if (readData.size() >= ExcelConstants.SAVE_DB_MAX_SIZE) {
            saveData();
            log.info("数据量达到{}条,保存内存数据到db", ExcelConstants.SAVE_DB_MAX_SIZE);
        }*/
//        if (dataCounts.get() >= ExcelConstants.SAVE_DB_MAX_SIZE) {
//            synchronized (RedisConst.SAVE_LOCK){
//                try {
//                    REDIS_LOCK.wait();
//                    saveData();
//                } catch (InterruptedException e) {
//                    throw new RuntimeException(e);
//                }
//
//                log.info("数据量达到{}条,保存内存数据到db", ExcelConstants.SAVE_DB_MAX_SIZE);
//                REDIS_LOCK.notify();
//            }
//
//        }else if (allCount.equals(count.get()+1)){
//            saveData();
//        }

            if (runTimes.equals(count.get())){
                saveData();
                synchronized (this.lock){
                    this.lock.notifyAll();
                }
            }
        }catch (Exception e){
            e.printStackTrace();
            synchronized (this.lock){
                this.lock.notifyAll();
            }
            throw new ImportException("参数找不到！"+(context.getCurrentRowNum()+1)+"行");
        }


    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        log.info("解析excel数据完成！！！");
        log.info("保存内存数据到db");
    }

    @Override
    public void invoke(HyPropertyReadVO object, AnalysisContext context) {
        runTimes++;
        if (MyObjectUtils.areAllFieldsNull(object)) {
            runTimes--;
            return;
        }
        ThreadPool.poolExecutor.execute(()-> threadInsert(object,context));
    }

    private void saveData() {
        if (readData.size() > 0) {
            mySaveData(readData);
            readData.clear();
        }
    }

    @Override
    protected void doSaveData(List<HyProperty> data) {

    }


    public  void  mySaveData(List<HyProperty> data){

        hyPropertyService.saveStuListWithBatch(data);
    }

}
